home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Dev / GNU-TILE-FORTH.lha / src / io.c! < prev    next >
Text File  |  1992-05-19  |  11KB  |  421 lines

  1. /*
  2.   C BASED FORTH-83 MULTI-TASKING IO MANAGEMENT
  3.  
  4.   Copyright (C) 1988-1990 by Mikael Patel
  5.  
  6.   Computer Aided Design Laboratory (CADLAB)
  7.   Department of Computer and Information Science
  8.   Linkoping University
  9.   S-581 83 LINKOPING
  10.   SWEDEN
  11.  
  12.   Email: mip@ida.liu.se
  13.   
  14.   Started on: 30 June 1988
  15.  
  16.   Last updated on: 26 June 1990
  17.  
  18.   Dependencies:
  19.        (cc) fcntl.h, errno.h, kernel.h, error.h, memory.h and io.h
  20.  
  21.   Description:
  22.        Handles low level access to Operating System to allow asynchronous
  23.        input and multi-tasking of Forth level processes while waiting for
  24.        buffer filling. File names are saved so that files are not reloaded. 
  25.   
  26.   Copying:
  27.        This program is free software; you can redistribute it and/or modify
  28.        it under the terms of the GNU General Public License as published by
  29.        the Free Software Foundation; either version 1, or (at your option)
  30.        any later version.
  31.  
  32.        This program is distributed in the hope that it will be useful,
  33.        but WITHOUT ANY WARRANTY; without even the implied warranty of
  34.        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  35.        GNU General Public License for more details.
  36.  
  37.        You should have received a copy of the GNU General Public License
  38.        along with this program; see the file COPYING.  If not, write to
  39.        the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  40.  
  41. */
  42.  
  43.  
  44. #include <fcntl.h>
  45. #include <errno.h>
  46. #include "kernel.h"
  47. #include "error.h"
  48. #include "memory.h"
  49. #include "io.h"
  50.  
  51.  
  52. /* EXTERNAL DEFINED IO DISPATCH ROUTINE, ENVIRONMENT ACCESS AND ERROR CODE */
  53.  
  54. extern VOID io_dispatch();
  55. extern CSTR getenv();
  56. extern INT  errno;
  57.  
  58.  
  59. /* MAXIMUM FILE AND PATH NAME STRING SIZES */
  60.  
  61. #define FILENAMESIZE 128
  62. #define PATHNAMESIZE 128
  63.  
  64.  
  65. /* INFILE BUFFERS STACK AND STACK POINTER */
  66.  
  67. #define INFSTACKSIZE 32
  68.  
  69. INFILE_BUFFER io_infstack[INFSTACKSIZE];
  70. INT io_infsp = -1;
  71.  
  72.  
  73. /* OUTFILE AND ERROR FILE VARIABLES */
  74.  
  75. FILE *io_outf;
  76. FILE *io_errf;
  77.  
  78.  
  79. /* STACK OF NAMES OF LOADED FILE */
  80.  
  81. #define INFILESSIZE 64
  82.  
  83. static CSTR infiles[INFILESSIZE];
  84. static INT infsp = -1;
  85.  
  86.  
  87. /* STACK OF FILE SEARCH PATHS */
  88.  
  89. #define PATHSSIZE 32
  90.  
  91. static CSTR paths[PATHSSIZE];
  92. static INT psp = -1;
  93.  
  94.  
  95. /* IO MANAGEMENT DEFINITONS */
  96.  
  97. INT io_path(pname, pos)
  98.     CSTR pname;            /* Pointer to path name */
  99.     INT pos;            /* Position to append */
  100. {
  101.     CHAR pathname[PATHNAMESIZE];    
  102.     INT plen = strlen(pname);
  103.     INT i;
  104.  
  105. printf("io_path-->%s\n",pname);
  106. printf("1\n");
  107.     /* Check for null path. Dont add these */
  108.     if (plen == 0) return IO_NO_ERROR;
  109.  
  110. printf("2\n");
  111.     /* Check if the path name is an environment variable */
  112.     if (pname[0] == '$') {
  113.  
  114.     /* Fetch the environment variables value */
  115.     char *paths = (char *) getenv((char *) pname + 1);
  116.  
  117.     /* If paths are available recursivly add them to the path list */
  118.     if (paths) {
  119.         while (*paths) {
  120.         char *p = pathname;
  121.  
  122.         /* Parse list of paths; directories seperated by colon */
  123.         while (*paths && *paths != ':') *p++ = *paths++;
  124.         *p++ = '\0'; 
  125.  
  126.         /* Append recursively */
  127.         (VOID) io_path(pathname, pos);
  128.  
  129.         /* Access next path if available */
  130.         if (*paths) paths++;
  131.         }
  132.         return IO_NO_ERROR;
  133.     }
  134.     else
  135.         return IO_UNKNOWN_PATH;
  136.     }
  137. printf("4\n");
  138.  
  139.     /* Check that the last character is a slash if not add it */
  140.     if (pname[plen - 1] != DIRSEPCHAR && pname[plen - 1] != ':') {
  141.     pname[plen++] = DIRSEPCHAR;
  142.     pname[plen] = '\0';
  143.     }
  144.  
  145. printf("%s\n",pname);
  146.  
  147.     /* Check if the path has already been defined */
  148.     for (i = 0; i <= psp; i++)
  149.     if (STREQ(paths[i], pname)) return IO_PATH_DEFINED;
  150.     
  151.     /* Check if space is available on path stack */
  152.     if (psp + 1 == PATHSSIZE) return IO_TOO_MANY_PATHS;
  153.  
  154.     /* Make space for the new path */
  155.     psp = psp + 1;
  156.     
  157.     /* Check where the path should be appended */
  158.     if (pos == IO_PATH_FIRST) {
  159.     for (i = psp; i > 0; i--) paths[i] = paths[i - 1];
  160.     pos = 0;
  161.     }
  162.     else pos = psp;
  163.  
  164.     /* Add path string att position given */
  165.     paths[pos] = strcpy((char *) malloc((unsigned) plen + 1), pname);
  166.  
  167.     return IO_NO_ERROR;
  168. }
  169.  
  170. VOID io_flush()
  171. {
  172.     /* Flush any waiting output */
  173.     (VOID) fflush(stdout);    
  174.  
  175.     /* Close all open files if not end of input stream */
  176.     if (io_not_eof()) {
  177.  
  178.     /* Close all files but lowest */
  179.     while (io_infsp > 0) (VOID) close(io_infstack[io_infsp--] -> fd);
  180.  
  181.     /* Close lowest file on file stack if not tty */
  182.     if (!isatty(io_infstack[io_infsp] -> fd))
  183.         (VOID) close(io_infstack[io_infsp--] -> fd);
  184.     }
  185. }
  186.  
  187. INT io_infile(fname)
  188.     CSTR fname;            /* Pointer to file name to open as input */
  189. {
  190.     CHAR filename[FILENAMESIZE];
  191.     INT i, j;
  192.     INT fd;
  193.     
  194.     /* Check for standard input as source */
  195.     if (fname == STDIN) {
  196.  
  197.     /* Check if space is available on file stack */
  198.     if (io_infsp + 1 == INFSTACKSIZE) return IO_TOO_MANY_FILES;
  199.  
  200.     /* Push standard input as source onto the file buffer stack */
  201.     io_infsp = io_infsp + 1;
  202.     io_infstack[io_infsp] -> fd = STDIN;
  203.     io_infstack[io_infsp] -> bufp = 0;
  204.     io_infstack[io_infsp] -> cc = 0;
  205.     io_infstack[io_infsp] -> fn = NIL;
  206.     io_infstack[io_infsp] -> ln = 1;
  207.     return IO_NO_ERROR;
  208.     }
  209.  
  210.     /* Expand the file name using the path stack and try opening the file */
  211.     for (i = 0; i <= psp; i++) {
  212.  
  213.     /* Build the new file name using a path */
  214.     (VOID) strcpy(filename, paths[i]);
  215.     (VOID) strcpy(filename + strlen(paths[i]), fname);
  216.  
  217.     /* Check if this file has already been loaded */
  218.     for (j = 0; j <= infsp; j++)
  219.         if (STREQ(infiles[j], filename)) return IO_FILE_INCLUDED;
  220.  
  221.     /* Try opening the file */
  222.     fd = open(filename, O_RDONLY);
  223.  
  224.     /* If no errors then save the file name and return file descriptor */
  225.     if (fd != -1) {
  226.  
  227.         /* Check if space is available on file stack */
  228.         if (io_infsp + 1 == INFSTACKSIZE) return IO_TOO_MANY_FILES;
  229.  
  230.         /* Push file onto the file buffer stack and use it as source */
  231.         infsp = infsp + 1;
  232.         infiles[infsp] = strcpy((char *) malloc((unsigned) strlen(filename) + 1), filename);
  233.         io_infstack[++io_infsp] -> fd = fd;
  234.         io_infstack[io_infsp] -> bufp = 0;
  235.         io_infstack[io_infsp] -> cc = 0;
  236.         io_infstack[io_infsp] -> fn = infiles[infsp];
  237.         io_infstack[io_infsp] -> ln = 1;
  238.         return fd;
  239.     }
  240.     }
  241.  
  242.     /* The file was not available so return error */
  243.     return IO_UNKNOWN_FILE;
  244. }
  245.  
  246.  
  247. INT io_fillbuf()
  248. {
  249.     BOOL nonblocking;
  250.  
  251.     /* Check io consistency and foreground task input only */
  252.     if (io_eof() || tp != foreground) error_fatal(0);
  253.     
  254.     /* Flush any waiting output if filling buffer from a terminal */
  255.     if (isatty(io_infstack[io_infsp] -> fd)) (VOID) fflush(stdout);
  256.  
  257.     /* Check for multi-tasking input operation */
  258.     if (tp != ((TASK) tp -> queue.succ)) {
  259.     (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, FNDELAY); 
  260.     tp -> status = IOWAITING;
  261.     nonblocking = TRUE;
  262.     }
  263.     else
  264.     nonblocking = FALSE;
  265.     
  266.     /* Allow multi-tasking during waiting for input */
  267.     for (;;) {
  268.  
  269.     /* Try reading a block from the current input stream */
  270.     if ((io_infstack[io_infsp] -> cc = read(io_infstack[io_infsp] -> fd,
  271.                         io_infstack[io_infsp] -> buf,
  272.                         BUFSIZE)) > 0) {
  273.  
  274.         /* Restore to non-blocking input from file and foreground */
  275.         if (nonblocking) {
  276.         (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0);
  277.         spush(foreground, TASK);
  278.         doresume();
  279.         tp -> status = RUNNING;
  280.         }
  281.  
  282.         /* Initiate the buffer pointer and return the first character */
  283.         io_infstack[io_infsp] -> bufp = 0;
  284.         return io_getchar();
  285.     }
  286.  
  287.     /* Did the read operation result in an end of file */
  288.     if (io_infstack[io_infsp] -> cc == 0 && errno != EWOULDBLOCK) {
  289.  
  290.         /* Set back the file mode to synchronous and close the file */
  291.         if (nonblocking) {
  292.         (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0);
  293.         spush(foreground, TASK);
  294.         doresume();
  295.         tp -> status = RUNNING;
  296.         }
  297.         (VOID) close(io_infstack[io_infsp--] -> fd); 
  298.         
  299.         /* Check if end of input source */
  300.         if (io_eof()) return IO_EOF;
  301.  
  302.         /* Get character from previous file buffer */
  303.         return io_getchar();
  304.     }
  305.  
  306.     /* Run forth level tasks while waiting for input */
  307.     if (tp == foreground) dodetach(); else doinner();
  308.     
  309.     /* Check if the task for empty, i.e., only the foreground */
  310.     if (tp == foreground && tp == ((TASK) tp -> queue.succ)) {
  311.         (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0); 
  312.         nonblocking = FALSE;
  313.     }
  314.     
  315.     /* Allow user extension of the io wait loop */
  316.     io_dispatch();
  317.     }
  318. }
  319.  
  320. VOID io_skip(skpchr)
  321.     CHAR skpchr;        /* Skip character */
  322. {
  323.     CHAR c;
  324.  
  325.     /* Skip all characters until skip termination character or end of file */
  326.     while (io_not_eof()) {
  327.     c = io_getchar();
  328.     if (c == '\n') io_newline();
  329.     if (c == skpchr) return;
  330.     }
  331. }
  332.  
  333. VOID io_scan(buf, brkchr)
  334.     CSTR buf;            /* Pointer to scan buffer */
  335.     CHAR brkchr;        /* Break character */
  336. {
  337.     CHAR c;
  338.     
  339.     /* Initiate buffer as null string */
  340.     *buf = '\0';
  341.  
  342.     /* Check for scanning until white space or special break character */
  343.     if (brkchr == ' ') {
  344.  
  345.     /* While not white space or end of file */
  346.     while (io_not_eof()) {
  347.         c = io_getchar();
  348.         if (c == '\n') io_newline();
  349.         if (ISSPACE(c)) break;
  350.         *buf++ = c;
  351.     }
  352.     }
  353.     else {
  354.  
  355.     /* While not the break character or end of file */
  356.     while (io_not_eof()) {
  357.         c = io_getchar();
  358.         if (c == '\n') io_newline();
  359.         if (c == brkchr) break;
  360.         *buf++ = c;
  361.     }
  362.     }
  363.     
  364.     /* End the string and return */
  365.     *buf = '\0';
  366.     return;
  367. }
  368.  
  369. VOID io_skipspace()
  370. {
  371.     CHAR c;
  372.     
  373.     /* Skip all white spaces */
  374.     while (io_not_eof()) {
  375.     c = io_getchar();
  376.     if (c == '\n') io_newline();
  377.     if (!ISSPACE(c)) break;
  378.     }
  379.     
  380.     /* Step back the buffer pointer */
  381.     if (io_not_eof()) io_infstack[io_infsp] -> bufp -= 1;
  382. }
  383.  
  384. VOID io_initiate(banner)
  385.     CSTR banner;        /* Initiate application message */
  386. {
  387.     INT i;
  388.  
  389.     /* Assign output and error file */
  390.     io_outf = stdout;
  391.     io_errf = stderr;
  392.  
  393.     /* Print banner and add initial paths */
  394.     (VOID) printf(banner);
  395.     (VOID) io_path("TILE:lib", IO_PATH_LAST);
  396.     (VOID) io_path("TILE:", IO_PATH_LAST);
  397.     (VOID) io_path("TILE:tst", IO_PATH_LAST);
  398.     (VOID) io_path("\"\"", IO_PATH_LAST);
  399.  
  400.  
  401.     /* Allocate file buffers */
  402.     for (i = 0; i < INFSTACKSIZE; i++) {
  403.     io_infstack[i] = (INFILE_BUFFER) malloc((unsigned) sizeof(file_buffer));
  404.     if (io_infstack[i] == NIL) {
  405.         (VOID) fprintf(io_errf, "io: cannot allocate file buffers\n");
  406.         exit(0);
  407.     }
  408.     }
  409.  
  410. }    
  411.     
  412. VOID io_finish()
  413. {
  414.     /* Flush any waiting output */
  415.     (VOID) fflush(stdout);    
  416.  
  417.     /* Close all open files */
  418.     while (io_not_eof()) (VOID) close(io_infstack[io_infsp--] -> fd);
  419. }
  420.  
  421.